package com.kmxd.ams.core.mybatisplus.extend;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.kmxd.ams.core.util.DynamicTableNameUtil;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * 动态设置字段
 *
 * @author zuolg
 */
@Slf4j
public class DynamicFieldInterceptor extends JsqlParserSupport implements InnerInterceptor {

  /** 文件及动态字段需处理 */
  private static final String fieldDocMp = "com.kmxd.ams.infra.arrange.mapper.DocumentMapper";

  /** 案卷级动态字段需处理 */
  private static final String fieldVolMp = "com.kmxd.ams.infra.arrange.mapper.VolumeMapper";

  /** 查询时处理逻辑 */
  @Override
  public void beforeQuery(
      Executor executor,
      MappedStatement ms,
      Object parameter,
      RowBounds rowBounds,
      ResultHandler resultHandler,
      BoundSql boundSql)
      throws SQLException {
    // 判断如果是文件、案卷则指定添加
    if (ms.getId().startsWith(fieldDocMp)) {
      PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
      // 通过 JSqlParser工具修改查询sql后执行
      mpBs.sql(parserSingle(mpBs.sql(), mpBs.parameterObject()));
    }
  }

  /** 增删改时 处理逻辑 */
  @Override
  public void beforePrepare(
      StatementHandler sh, Connection connection, Integer transactionTimeout) {
    PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
    MappedStatement ms = mpSh.mappedStatement();
    SqlCommandType sct = ms.getSqlCommandType();
    // 增改调用 JSqlParser工具修改sql后执行
    if ((sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE)) {
      if (ms.getId().startsWith(fieldDocMp)) {
        PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
        mpBs.sql(parserMulti(mpBs.sql(), mpBs.parameterObject()));
      }
    }
  }

  @Override
  protected void processDelete(Delete delete, int index, String sql, Object obj) {
    log.debug("删除前调用,可修改sql");
  }

  /** 以处理查询sql为例,增删改的实现可根据自己的业务实现 */
  @Override
  protected void processSelect(Select select, int index, String sql, Object obj) {
    // 此处处理select逻辑 将字符串拼接上 双引号
    SelectBody selectBody = select.getSelectBody();
    if (selectBody instanceof PlainSelect) {
      reformatPlainSelect((PlainSelect) selectBody);
    }
  }

  @Override
  protected void processInsert(Insert insert, int index, String sql, Object obj) {
    log.debug("新增前调用,可修改sql");
  }

  @Override
  protected void processUpdate(Update update, int index, String sql, Object obj) {
    List<String> fields = DynamicTableNameUtil.getFields();
    log.debug("修改调用,可修改sql！");
    if (ObjectUtil.isNotEmpty(fields) && !fields.isEmpty()) {

      Map<String, Object> map = (Map<String, Object>) obj;
      Object jsonObj = map.get("param1");
      JSONObject object =
          ObjectUtil.isNotEmpty(jsonObj) ? JSONUtil.parseObj(jsonObj) : new JSONObject();

      fields.forEach(
          key -> {
            String val = object.getStr(key, null);
            Column column = new Column(key);
            Expression expression = new StringValue(val);
            update.addUpdateSet(column, expression);
          });
    }
  }

  /**
   * 重新格式化 查询语句
   *
   * @param plainSelect 查询语句
   * @return 格式化的查询语句
   */
  public void reformatPlainSelect(PlainSelect plainSelect) {
    List<String> fields = DynamicTableNameUtil.getFields();
    if (ObjectUtil.isNotEmpty(fields) && !fields.isEmpty()) {
      // 处理要查询的字段
      List<SelectItem> selectItems = plainSelect.getSelectItems();
      fields.forEach(
          key -> {
            // 此处逻辑为动态添加查询处理字段
            Column columnExp = new Column(key);
            SelectExpressionItem expressionItem = new SelectExpressionItem(columnExp);
            selectItems.add(expressionItem);
          });

      // 处理查询条件
      plainSelect.setSelectItems(selectItems);
    }
  }
}
